#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/epoll.h>
#include<string.h>
#include<arpa/inet.h>

int main(){

    //1、创建用于监听的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);

    //2、绑定套接字
    struct sockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = INADDR_ANY;
    saddr.sin_port = htons(9999);
    bind(lfd, (struct sockaddr*)&saddr,sizeof(saddr));

    //3、监听
    listen(lfd, 8);

    //调用一个epoll_creat()创建一个epoll实例
    //获得一个文件描述符，通过这个文件描述符操作内核中的epoll实例
    int epfd = epoll_create(100);

    //将需要监听的文件描述符信息添加到epoll实例中
    struct epoll_event epev;
    epev.events = EPOLLIN;   //检测读事件
    epev.data.fd = lfd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &epev);

    struct epoll_event epevs[1024];   //表示就绪队列，里面存放发生改变的epoll事件

    while(1){
        int ret = epoll_wait(epfd, epevs, 1024, -1);
        if(ret == -1){
            perror("epoll_wait");
            exit(-1);
        }
        printf("ret = %d\n", ret);
        for(int i = 0; i < ret; ++i){
            int curfd = epevs[i].data.fd;
            if( curfd = lfd){
                //表示监听的文件描述符有数据到达，有客户端连接进来
                struct sockaddr_in cliaddr;
                int len = sizeof(cliaddr);
                int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);

                epev.events = EPOLLIN;
                epev.data.fd = cfd;
                //将新获得的用于通信的文件描述符放入之前的epoll实例中
                epoll_ctl(epfd,EPOLL_CTL_ADD, cfd, &epev);
            }else{
                //有数据到达，需要通信
                char revBuf[1024] = {0};
                int datalen = read(curfd, revBuf, sizeof(revBuf));
                if(datalen == -1){
                    perror("read");
                    exit(-1);
                }else if(datalen == 0){
                    printf("client closed...\n");
                    //将文件描述符从事件中删除
                    epoll_ctl(epfd,EPOLL_CTL_DEL, curfd, NULL);
                    close(curfd);
                }else if(datalen > 0){
                    printf("read buf = %s\n", revBuf);
                    write(curfd, revBuf, strlen(revBuf)+1);
                }
            }
        }
    }
    close(lfd);
    close(epfd);
    return 0;
}